package rpcHandler

import (
	"context"
	"fmt"
	baseLog "gitee.com/zaiqiang231/go-base-app/base_app/log"
	"gitee.com/zaiqiang231/go-base-app/base_app/store"
	"gitee.com/zaiqiang231/go-base-sms/app/config"
	"gitee.com/zaiqiang231/go-base-sms/app/rpc/proto"
	"gitee.com/zaiqiang231/go-base-sms/app/util"
	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
	dysmsapi "github.com/alibabacloud-go/dysmsapi-20170525/v3/client"
	"github.com/alibabacloud-go/tea/tea"
	"github.com/pkg/errors"
	"math/rand"
	"strconv"
	"sync"
	"time"
)

var (
	smsSever     *SmsServer
	onceSmsSever sync.Once
)

type SmsServer struct {
	Client *dysmsapi.Client
	Rand   *rand.Rand
}

func GetSmsServer() (*SmsServer, error) {
	onceSmsSever.Do(func() {
		smsSever = &SmsServer{}
		config := &openapi.Config{
			AccessKeyId:     tea.String(config.GlobalAppConfig.AliSmsConfig.AccessKeyId),
			AccessKeySecret: tea.String(config.GlobalAppConfig.AliSmsConfig.AccessKeySecret),
		}
		// 访问的域名
		config.Endpoint = tea.String("dysmsapi.aliyuncs.com")

		client, err := dysmsapi.NewClient(config)
		if err != nil {
			baseLog.Fatalf("Failed to init smsServer : %s", err.Error())
		}
		smsSever.Client = client
		smsSever.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
	})

	if smsSever == nil {
		return nil, fmt.Errorf("got nil server")
	}

	return smsSever, nil
}

func (s SmsServer) SendSmsCode(ctx context.Context, request *proto.SendSmsRequest) (*proto.SendSmsResponse, error) {

	resultWhiteGet := store.GetRedisStore().Get(ctx, util.GetWhiteRedisKey(request.Phone))
	tmperr := resultWhiteGet.Err()
	if tmperr == nil && len(resultWhiteGet.Val()) > 0 {
		return &proto.SendSmsResponse{
			Msg:  "success",
			Code: 0,
		}, nil
	}

	resultGet := store.GetRedisStore().Get(ctx, util.GetRedisKey(request.Phone))
	err := resultGet.Err()

	var smsCode string
	resend := false
	if err == nil && len(resultGet.Val()) > 0 {
		smsCode = resultGet.Val()
		resend = true
	} else {
		smsCode = strconv.Itoa(s.Rand.Intn(899999) + 100000)
	}

	sendSmsRequest := &dysmsapi.SendSmsRequest{
		SignName:      tea.String("zcamp"),
		TemplateCode:  tea.String("SMS_464040916"),
		PhoneNumbers:  tea.String(request.Phone),
		TemplateParam: tea.String(fmt.Sprintf("{\"code\":\"%s\"}", smsCode)),
	}
	sendSmsResponse, err := s.Client.SendSms(sendSmsRequest)
	if err != nil {
		return nil, err
	}

	if *sendSmsResponse.Body.Code != "OK" {
		return nil, errors.New(*sendSmsResponse.Body.Message)
	}

	if !resend {
		resultSet := store.GetRedisStore().Set(ctx, util.GetRedisKey(request.Phone), smsCode, 5*time.Minute)
		err = resultSet.Err()
		if err != nil {
			return nil, err
		}
	}

	return &proto.SendSmsResponse{
		Msg:  "success",
		Code: 0,
	}, nil
}

func (s SmsServer) CheckSmsCode(ctx context.Context, request *proto.CheckSmsRequest) (*proto.CheckSmsResponse, error) {

	resultWhiteGet := store.GetRedisStore().Get(ctx, util.GetWhiteRedisKey(request.Phone))
	tmperr := resultWhiteGet.Err()
	if tmperr == nil && len(resultWhiteGet.Val()) > 0 {
		if resultWhiteGet.Val() != request.SmsCode {
			return nil, errors.New("验证码不正确")
		}
	} else {
		key := util.GetRedisKey(request.Phone)
		result := store.GetRedisStore().Get(ctx, key)
		err := result.Err()
		if err != nil {
			return nil, err
		}

		if result.Val() != request.SmsCode {
			return nil, errors.New("验证码不正确")
		}

		resultDel := store.GetRedisStore().Del(ctx, key)
		err = resultDel.Err()
		if err != nil {
			return nil, err
		}
	}

	return &proto.CheckSmsResponse{
		Msg:  "success",
		Code: 0,
	}, nil
}
